home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / Net / SMTP.php < prev    next >
Encoding:
PHP Script  |  2006-04-07  |  30.1 KB  |  1,006 lines

  1. <?php
  2. /* vim: set expandtab softtabstop=4 tabstop=4 shiftwidth=4: */
  3. // +----------------------------------------------------------------------+
  4. // | PHP Version 4                                                        |
  5. // +----------------------------------------------------------------------+
  6. // | Copyright (c) 1997-2003 The PHP Group                                |
  7. // +----------------------------------------------------------------------+
  8. // | This source file is subject to version 2.02 of the PHP license,      |
  9. // | that is bundled with this package in the file LICENSE, and is        |
  10. // | available at through the world-wide-web at                           |
  11. // | http://www.php.net/license/2_02.txt.                                 |
  12. // | If you did not receive a copy of the PHP license and are unable to   |
  13. // | obtain it through the world-wide-web, please send a note to          |
  14. // | license@php.net so we can mail you a copy immediately.               |
  15. // +----------------------------------------------------------------------+
  16. // | Authors: Chuck Hagenbuch <chuck@horde.org>                           |
  17. // |          Jon Parise <jon@php.net>                                    |
  18. // |          Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>      |
  19. // +----------------------------------------------------------------------+
  20. //
  21. // $Id: SMTP.php,v 1.55 2006/02/06 06:00:22 jon Exp $
  22.  
  23. require_once 'PEAR.php';
  24. require_once 'Net/Socket.php';
  25.  
  26. /**
  27.  * Provides an implementation of the SMTP protocol using PEAR's
  28.  * Net_Socket:: class.
  29.  *
  30.  * @package Net_SMTP
  31.  * @author  Chuck Hagenbuch <chuck@horde.org>
  32.  * @author  Jon Parise <jon@php.net>
  33.  * @author  Damian Alejandro Fernandez Sosa <damlists@cnba.uba.ar>
  34.  *
  35.  * @example basic.php   A basic implementation of the Net_SMTP package.
  36.  */
  37. class Net_SMTP
  38. {
  39.     /**
  40.      * The server to connect to.
  41.      * @var string
  42.      * @access public
  43.      */
  44.     var $host = 'localhost';
  45.  
  46.     /**
  47.      * The port to connect to.
  48.      * @var int
  49.      * @access public
  50.      */
  51.     var $port = 25;
  52.  
  53.     /**
  54.      * The value to give when sending EHLO or HELO.
  55.      * @var string
  56.      * @access public
  57.      */
  58.     var $localhost = 'localhost';
  59.  
  60.     /**
  61.      * List of supported authentication methods, in preferential order.
  62.      * @var array
  63.      * @access public
  64.      */
  65.     var $auth_methods = array('DIGEST-MD5', 'CRAM-MD5', 'LOGIN', 'PLAIN');
  66.  
  67.     /**
  68.      * Should debugging output be enabled?
  69.      * @var boolean
  70.      * @access private
  71.      */
  72.     var $_debug = false;
  73.  
  74.     /**
  75.      * The socket resource being used to connect to the SMTP server.
  76.      * @var resource
  77.      * @access private
  78.      */
  79.     var $_socket = null;
  80.  
  81.     /**
  82.      * The most recent server response code.
  83.      * @var int
  84.      * @access private
  85.      */
  86.     var $_code = -1;
  87.  
  88.     /**
  89.      * The most recent server response arguments.
  90.      * @var array
  91.      * @access private
  92.      */
  93.     var $_arguments = array();
  94.  
  95.     /**
  96.      * Stores detected features of the SMTP server.
  97.      * @var array
  98.      * @access private
  99.      */
  100.     var $_esmtp = array();
  101.  
  102.     /**
  103.      * Instantiates a new Net_SMTP object, overriding any defaults
  104.      * with parameters that are passed in.
  105.      *
  106.      * If you have SSL support in PHP, you can connect to a server
  107.      * over SSL using an 'ssl://' prefix:
  108.      *
  109.      *   // 465 is a common smtps port.
  110.      *   $smtp = new Net_SMTP('ssl://mail.host.com', 465);
  111.      *   $smtp->connect();
  112.      *
  113.      * @param string  $host       The server to connect to.
  114.      * @param integer $port       The port to connect to.
  115.      * @param string  $localhost  The value to give when sending EHLO or HELO.
  116.      *
  117.      * @access  public
  118.      * @since   1.0
  119.      */
  120.     function Net_SMTP($host = null, $port = null, $localhost = null)
  121.     {
  122.         if (isset($host)) $this->host = $host;
  123.         if (isset($port)) $this->port = $port;
  124.         if (isset($localhost)) $this->localhost = $localhost;
  125.  
  126.         $this->_socket = &new Net_Socket();
  127.  
  128.         /*
  129.          * Include the Auth_SASL package.  If the package is not available,
  130.          * we disable the authentication methods that depend upon it.
  131.          */
  132.         if ((@include_once 'Auth/SASL.php') === false) {
  133.             $pos = array_search('DIGEST-MD5', $this->auth_methods);
  134.             unset($this->auth_methods[$pos]);
  135.             $pos = array_search('CRAM-MD5', $this->auth_methods);
  136.             unset($this->auth_methods[$pos]);
  137.         }
  138.     }
  139.  
  140.     /**
  141.      * Set the value of the debugging flag.
  142.      *
  143.      * @param   boolean $debug      New value for the debugging flag.
  144.      *
  145.      * @access  public
  146.      * @since   1.1.0
  147.      */
  148.     function setDebug($debug)
  149.     {
  150.         $this->_debug = $debug;
  151.     }
  152.  
  153.     /**
  154.      * Send the given string of data to the server.
  155.      *
  156.      * @param   string  $data       The string of data to send.
  157.      *
  158.      * @return  mixed   True on success or a PEAR_Error object on failure.
  159.      *
  160.      * @access  private
  161.      * @since   1.1.0
  162.      */
  163.     function _send($data)
  164.     {
  165.         if ($this->_debug) {
  166.             echo "DEBUG: Send: $data\n";
  167.         }
  168.  
  169.         if (PEAR::isError($error = $this->_socket->write($data))) {
  170.             return PEAR::raiseError('Failed to write to socket: ' .
  171.                                     $error->getMessage());
  172.         }
  173.  
  174.         return true;
  175.     }
  176.  
  177.     /**
  178.      * Send a command to the server with an optional string of
  179.      * arguments.  A carriage return / linefeed (CRLF) sequence will
  180.      * be appended to each command string before it is sent to the
  181.      * SMTP server - an error will be thrown if the command string
  182.      * already contains any newline characters. Use _send() for
  183.      * commands that must contain newlines.
  184.      *
  185.      * @param   string  $command    The SMTP command to send to the server.
  186.      * @param   string  $args       A string of optional arguments to append
  187.      *                              to the command.
  188.      *
  189.      * @return  mixed   The result of the _send() call.
  190.      *
  191.      * @access  private
  192.      * @since   1.1.0
  193.      */
  194.     function _put($command, $args = '')
  195.     {
  196.         if (!empty($args)) {
  197.             $command .= ' ' . $args;
  198.         }
  199.  
  200.         if (strcspn($command, "\r\n") !== strlen($command)) {
  201.             return PEAR::raiseError('Commands cannot contain newlines');
  202.         }
  203.  
  204.         return $this->_send($command . "\r\n");
  205.     }
  206.  
  207.     /**
  208.      * Read a reply from the SMTP server.  The reply consists of a response
  209.      * code and a response message.
  210.      *
  211.      * @param   mixed   $valid      The set of valid response codes.  These
  212.      *                              may be specified as an array of integer
  213.      *                              values or as a single integer value.
  214.      *
  215.      * @return  mixed   True if the server returned a valid response code or
  216.      *                  a PEAR_Error object is an error condition is reached.
  217.      *
  218.      * @access  private
  219.      * @since   1.1.0
  220.      *
  221.      * @see     getResponse
  222.      */
  223.     function _parseResponse($valid)
  224.     {
  225.         $this->_code = -1;
  226.         $this->_arguments = array();
  227.  
  228.         while ($line = $this->_socket->readLine()) {
  229.             if ($this->_debug) {
  230.                 echo "DEBUG: Recv: $line\n";
  231.             }
  232.  
  233.             /* If we receive an empty line, the connection has been closed. */
  234.             if (empty($line)) {
  235.                 $this->disconnect();
  236.                 return PEAR::raiseError('Connection was unexpectedly closed');
  237.             }
  238.  
  239.             /* Read the code and store the rest in the arguments array. */
  240.             $code = substr($line, 0, 3);
  241.             $this->_arguments[] = trim(substr($line, 4));
  242.  
  243.             /* Check the syntax of the response code. */
  244.             if (is_numeric($code)) {
  245.                 $this->_code = (int)$code;
  246.             } else {
  247.                 $this->_code = -1;
  248.                 break;
  249.             }
  250.  
  251.             /* If this is not a multiline response, we're done. */
  252.             if (substr($line, 3, 1) != '-') {
  253.                 break;
  254.             }
  255.         }
  256.  
  257.         /* Compare the server's response code with the valid code. */
  258.         if (is_int($valid) && ($this->_code === $valid)) {
  259.             return true;
  260.         }
  261.  
  262.         /* If we were given an array of valid response codes, check each one. */
  263.         if (is_array($valid)) {
  264.             foreach ($valid as $valid_code) {
  265.                 if ($this->_code === $valid_code) {
  266.                     return true;
  267.                 }
  268.             }
  269.         }
  270.  
  271.         return PEAR::raiseError('Invalid response code received from server');
  272.     }
  273.  
  274.     /**
  275.      * Return a 2-tuple containing the last response from the SMTP server.
  276.      *
  277.      * @return  array   A two-element array: the first element contains the
  278.      *                  response code as an integer and the second element
  279.      *                  contains the response's arguments as a string.
  280.      *
  281.      * @access  public
  282.      * @since   1.1.0
  283.      */
  284.     function getResponse()
  285.     {
  286.         return array($this->_code, join("\n", $this->_arguments));
  287.     }
  288.  
  289.     /**
  290.      * Attempt to connect to the SMTP server.
  291.      *
  292.      * @param   int     $timeout    The timeout value (in seconds) for the
  293.      *                              socket connection.
  294.      * @param   bool    $persistent Should a persistent socket connection
  295.      *                              be used?
  296.      *
  297.      * @return mixed Returns a PEAR_Error with an error message on any
  298.      *               kind of failure, or true on success.
  299.      * @access public
  300.      * @since  1.0
  301.      */
  302.     function connect($timeout = null, $persistent = false)
  303.     {
  304.         $result = $this->_socket->connect($this->host, $this->port,
  305.                                           $persistent, $timeout);
  306.         if (PEAR::isError($result)) {
  307.             return PEAR::raiseError('Failed to connect socket: ' .
  308.                                     $result->getMessage());
  309.         }
  310.  
  311.         if (PEAR::isError($error = $this->_parseResponse(220))) {
  312.             return $error;
  313.         }
  314.         if (PEAR::isError($error = $this->_negotiate())) {
  315.             return $error;
  316.         }
  317.  
  318.         return true;
  319.     }
  320.  
  321.     /**
  322.      * Attempt to disconnect from the SMTP server.
  323.      *
  324.      * @return mixed Returns a PEAR_Error with an error message on any
  325.      *               kind of failure, or true on success.
  326.      * @access public
  327.      * @since  1.0
  328.      */
  329.     function disconnect()
  330.     {
  331.         if (PEAR::isError($error = $this->_put('QUIT'))) {
  332.             return $error;
  333.         }
  334.         if (PEAR::isError($error = $this->_parseResponse(221))) {
  335.             return $error;
  336.         }
  337.         if (PEAR::isError($error = $this->_socket->disconnect())) {
  338.             return PEAR::raiseError('Failed to disconnect socket: ' .
  339.                                     $error->getMessage());
  340.         }
  341.  
  342.         return true;
  343.     }
  344.  
  345.     /**
  346.      * Attempt to send the EHLO command and obtain a list of ESMTP
  347.      * extensions available, and failing that just send HELO.
  348.      *
  349.      * @return mixed Returns a PEAR_Error with an error message on any
  350.      *               kind of failure, or true on success.
  351.      *
  352.      * @access private
  353.      * @since  1.1.0
  354.      */
  355.     function _negotiate()
  356.     {
  357.         if (PEAR::isError($error = $this->_put('EHLO', $this->localhost))) {
  358.             return $error;
  359.         }
  360.  
  361.         if (PEAR::isError($this->_parseResponse(250))) {
  362.             /* If we receive a 503 response, we're already authenticated. */
  363.             if ($this->_code === 503) {
  364.                 return true;
  365.             }
  366.  
  367.             /* If the EHLO failed, try the simpler HELO command. */
  368.             if (PEAR::isError($error = $this->_put('HELO', $this->localhost))) {
  369.                 return $error;
  370.             }
  371.             if (PEAR::isError($this->_parseResponse(250))) {
  372.                 return PEAR::raiseError('HELO was not accepted: ', $this->_code);
  373.             }
  374.  
  375.             return true;
  376.         }
  377.  
  378.         foreach ($this->_arguments as $argument) {
  379.             $verb = strtok($argument, ' ');
  380.             $arguments = substr($argument, strlen($verb) + 1,
  381.                                 strlen($argument) - strlen($verb) - 1);
  382.             $this->_esmtp[$verb] = $arguments;
  383.         }
  384.  
  385.         return true;
  386.     }
  387.  
  388.     /**
  389.      * Returns the name of the best authentication method that the server
  390.      * has advertised.
  391.      *
  392.      * @return mixed    Returns a string containing the name of the best
  393.      *                  supported authentication method or a PEAR_Error object
  394.      *                  if a failure condition is encountered.
  395.      * @access private
  396.      * @since  1.1.0
  397.      */
  398.     function _getBestAuthMethod()
  399.     {
  400.         $available_methods = explode(' ', $this->_esmtp['AUTH']);
  401.  
  402.         foreach ($this->auth_methods as $method) {
  403.             if (in_array($method, $available_methods)) {
  404.                 return $method;
  405.             }
  406.         }
  407.  
  408.         return PEAR::raiseError('No supported authentication methods');
  409.     }
  410.  
  411.     /**
  412.      * Attempt to do SMTP authentication.
  413.      *
  414.      * @param string The userid to authenticate as.
  415.      * @param string The password to authenticate with.
  416.      * @param string The requested authentication method.  If none is
  417.      *               specified, the best supported method will be used.
  418.      *
  419.      * @return mixed Returns a PEAR_Error with an error message on any
  420.      *               kind of failure, or true on success.
  421.      * @access public
  422.      * @since  1.0
  423.      */
  424.     function auth($uid, $pwd , $method = '')
  425.     {
  426.         if (empty($this->_esmtp['AUTH'])) {
  427.             return PEAR::raiseError('SMTP server does no support authentication');
  428.         }
  429.  
  430.         /* If no method has been specified, get the name of the best
  431.          * supported method advertised by the SMTP server. */
  432.         if (empty($method)) {
  433.             if (PEAR::isError($method = $this->_getBestAuthMethod())) {
  434.                 /* Return the PEAR_Error object from _getBestAuthMethod(). */
  435.                 return $method;
  436.             }
  437.         } else {
  438.             $method = strtoupper($method);
  439.             if (!in_array($method, $this->auth_methods)) {
  440.                 return PEAR::raiseError("$method is not a supported authentication method");
  441.             }
  442.         }
  443.  
  444.         switch ($method) {
  445.             case 'DIGEST-MD5':
  446.                 $result = $this->_authDigest_MD5($uid, $pwd);
  447.                 break;
  448.             case 'CRAM-MD5':
  449.                 $result = $this->_authCRAM_MD5($uid, $pwd);
  450.                 break;
  451.             case 'LOGIN':
  452.                 $result = $this->_authLogin($uid, $pwd);
  453.                 break;
  454.             case 'PLAIN':
  455.                 $result = $this->_authPlain($uid, $pwd);
  456.                 break;
  457.             default:
  458.                 $result = PEAR::raiseError("$method is not a supported authentication method");
  459.                 break;
  460.         }
  461.  
  462.         /* If an error was encountered, return the PEAR_Error object. */
  463.         if (PEAR::isError($result)) {
  464.             return $result;
  465.         }
  466.  
  467.         return true;
  468.     }
  469.  
  470.     /**
  471.      * Authenticates the user using the DIGEST-MD5 method.
  472.      *
  473.      * @param string The userid to authenticate as.
  474.      * @param string The password to authenticate with.
  475.      *
  476.      * @return mixed Returns a PEAR_Error with an error message on any
  477.      *               kind of failure, or true on success.
  478.      * @access private
  479.      * @since  1.1.0
  480.      */
  481.     function _authDigest_MD5($uid, $pwd)
  482.     {
  483.         if (PEAR::isError($error = $this->_put('AUTH', 'DIGEST-MD5'))) {
  484.             return $error;
  485.         }
  486.         /* 334: Continue authentication request */
  487.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  488.             /* 503: Error: already authenticated */
  489.             if ($this->_code === 503) {
  490.                 return true;
  491.             }
  492.             return $error;
  493.         }
  494.  
  495.         $challenge = base64_decode($this->_arguments[0]);
  496.         $digest = &Auth_SASL::factory('digestmd5');
  497.         $auth_str = base64_encode($digest->getResponse($uid, $pwd, $challenge,
  498.                                                        $this->host, "smtp"));
  499.  
  500.         if (PEAR::isError($error = $this->_put($auth_str))) {
  501.             return $error;
  502.         }
  503.         /* 334: Continue authentication request */
  504.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  505.             return $error;
  506.         }
  507.  
  508.         /* We don't use the protocol's third step because SMTP doesn't
  509.          * allow subsequent authentication, so we just silently ignore
  510.          * it. */
  511.         if (PEAR::isError($error = $this->_put(' '))) {
  512.             return $error;
  513.         }
  514.         /* 235: Authentication successful */
  515.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  516.             return $error;
  517.         }
  518.     }
  519.  
  520.     /**
  521.      * Authenticates the user using the CRAM-MD5 method.
  522.      *
  523.      * @param string The userid to authenticate as.
  524.      * @param string The password to authenticate with.
  525.      *
  526.      * @return mixed Returns a PEAR_Error with an error message on any
  527.      *               kind of failure, or true on success.
  528.      * @access private
  529.      * @since  1.1.0
  530.      */
  531.     function _authCRAM_MD5($uid, $pwd)
  532.     {
  533.         if (PEAR::isError($error = $this->_put('AUTH', 'CRAM-MD5'))) {
  534.             return $error;
  535.         }
  536.         /* 334: Continue authentication request */
  537.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  538.             /* 503: Error: already authenticated */
  539.             if ($this->_code === 503) {
  540.                 return true;
  541.             }
  542.             return $error;
  543.         }
  544.  
  545.         $challenge = base64_decode($this->_arguments[0]);
  546.         $cram = &Auth_SASL::factory('crammd5');
  547.         $auth_str = base64_encode($cram->getResponse($uid, $pwd, $challenge));
  548.  
  549.         if (PEAR::isError($error = $this->_put($auth_str))) {
  550.             return $error;
  551.         }
  552.  
  553.         /* 235: Authentication successful */
  554.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  555.             return $error;
  556.         }
  557.     }
  558.  
  559.     /**
  560.      * Authenticates the user using the LOGIN method.
  561.      *
  562.      * @param string The userid to authenticate as.
  563.      * @param string The password to authenticate with.
  564.      *
  565.      * @return mixed Returns a PEAR_Error with an error message on any
  566.      *               kind of failure, or true on success.
  567.      * @access private
  568.      * @since  1.1.0
  569.      */
  570.     function _authLogin($uid, $pwd)
  571.     {
  572.         if (PEAR::isError($error = $this->_put('AUTH', 'LOGIN'))) {
  573.             return $error;
  574.         }
  575.         /* 334: Continue authentication request */
  576.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  577.             /* 503: Error: already authenticated */
  578.             if ($this->_code === 503) {
  579.                 return true;
  580.             }
  581.             return $error;
  582.         }
  583.  
  584.         if (PEAR::isError($error = $this->_put(base64_encode($uid)))) {
  585.             return $error;
  586.         }
  587.         /* 334: Continue authentication request */
  588.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  589.             return $error;
  590.         }
  591.  
  592.         if (PEAR::isError($error = $this->_put(base64_encode($pwd)))) {
  593.             return $error;
  594.         }
  595.  
  596.         /* 235: Authentication successful */
  597.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  598.             return $error;
  599.         }
  600.  
  601.         return true;
  602.     }
  603.  
  604.     /**
  605.      * Authenticates the user using the PLAIN method.
  606.      *
  607.      * @param string The userid to authenticate as.
  608.      * @param string The password to authenticate with.
  609.      *
  610.      * @return mixed Returns a PEAR_Error with an error message on any
  611.      *               kind of failure, or true on success.
  612.      * @access private
  613.      * @since  1.1.0
  614.      */
  615.     function _authPlain($uid, $pwd)
  616.     {
  617.         if (PEAR::isError($error = $this->_put('AUTH', 'PLAIN'))) {
  618.             return $error;
  619.         }
  620.         /* 334: Continue authentication request */
  621.         if (PEAR::isError($error = $this->_parseResponse(334))) {
  622.             /* 503: Error: already authenticated */
  623.             if ($this->_code === 503) {
  624.                 return true;
  625.             }
  626.             return $error;
  627.         }
  628.  
  629.         $auth_str = base64_encode(chr(0) . $uid . chr(0) . $pwd);
  630.  
  631.         if (PEAR::isError($error = $this->_put($auth_str))) {
  632.             return $error;
  633.         }
  634.  
  635.         /* 235: Authentication successful */
  636.         if (PEAR::isError($error = $this->_parseResponse(235))) {
  637.             return $error;
  638.         }
  639.  
  640.         return true;
  641.     }
  642.  
  643.     /**
  644.      * Send the HELO command.
  645.      *
  646.      * @param string The domain name to say we are.
  647.      *
  648.      * @return mixed Returns a PEAR_Error with an error message on any
  649.      *               kind of failure, or true on success.
  650.      * @access public
  651.      * @since  1.0
  652.      */
  653.     function helo($domain)
  654.     {
  655.         if (PEAR::isError($error = $this->_put('HELO', $domain))) {
  656.             return $error;
  657.         }
  658.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  659.             return $error;
  660.         }
  661.  
  662.         return true;
  663.     }
  664.  
  665.     /**
  666.      * Send the MAIL FROM: command.
  667.      *
  668.      * @param string $sender    The sender (reverse path) to set.
  669.      * @param string $params    String containing additional MAIL parameters,
  670.      *                          such as the NOTIFY flags defined by RFC 1891
  671.      *                          or the VERP protocol.
  672.      *
  673.      *                          If $params is an array, only the 'verp' option
  674.      *                          is supported.  If 'verp' is true, the XVERP
  675.      *                          parameter is appended to the MAIL command.  If
  676.      *                          the 'verp' value is a string, the full
  677.      *                          XVERP=value parameter is appended.
  678.      *
  679.      * @return mixed Returns a PEAR_Error with an error message on any
  680.      *               kind of failure, or true on success.
  681.      * @access public
  682.      * @since  1.0
  683.      */
  684.     function mailFrom($sender, $params = null)
  685.     {
  686.         $args = "FROM:<$sender>";
  687.  
  688.         /* Support the deprecated array form of $params. */
  689.         if (is_array($params) && isset($params['verp'])) {
  690.             /* XVERP */
  691.             if ($params['verp'] === true) {
  692.                 $args .= ' XVERP';
  693.  
  694.             /* XVERP=something */
  695.             } elseif (trim($params['verp'])) {
  696.                 $args .= ' XVERP=' . $params['verp'];
  697.             }
  698.         } elseif (is_string($params)) {
  699.             $args .= ' ' . $params;
  700.         }
  701.  
  702.         if (PEAR::isError($error = $this->_put('MAIL', $args))) {
  703.             return $error;
  704.         }
  705.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  706.             return $error;
  707.         }
  708.  
  709.         return true;
  710.     }
  711.  
  712.     /**
  713.      * Send the RCPT TO: command.
  714.      *
  715.      * @param string $recipient The recipient (forward path) to add.
  716.      * @param string $params    String containing additional RCPT parameters,
  717.      *                          such as the NOTIFY flags defined by RFC 1891.
  718.      *
  719.      * @return mixed Returns a PEAR_Error with an error message on any
  720.      *               kind of failure, or true on success.
  721.      *
  722.      * @access public
  723.      * @since  1.0
  724.      */
  725.     function rcptTo($recipient, $params = null)
  726.     {
  727.         $args = "TO:<$recipient>";
  728.         if (is_string($params)) {
  729.             $args .= ' ' . $params;
  730.         }
  731.  
  732.         if (PEAR::isError($error = $this->_put('RCPT', $args))) {
  733.             return $error;
  734.         }
  735.         if (PEAR::isError($error = $this->_parseResponse(array(250, 251)))) {
  736.             return $error;
  737.         }
  738.  
  739.         return true;
  740.     }
  741.  
  742.     /**
  743.      * Quote the data so that it meets SMTP standards.
  744.      *
  745.      * This is provided as a separate public function to facilitate
  746.      * easier overloading for the cases where it is desirable to
  747.      * customize the quoting behavior.
  748.      *
  749.      * @param string $data  The message text to quote. The string must be passed
  750.      *                      by reference, and the text will be modified in place.
  751.      *
  752.      * @access public
  753.      * @since  1.2
  754.      */
  755.     function quotedata(&$data)
  756.     {
  757.         /* Change Unix (\n) and Mac (\r) linefeeds into
  758.          * Internet-standard CRLF (\r\n) linefeeds. */
  759.         $data = preg_replace(array('/(?<!\r)\n/','/\r(?!\n)/'), "\r\n", $data);
  760.  
  761.         /* Because a single leading period (.) signifies an end to the
  762.          * data, legitimate leading periods need to be "doubled"
  763.          * (e.g. '..'). */
  764.         $data = str_replace("\n.", "\n..", $data);
  765.     }
  766.  
  767.     /**
  768.      * Send the DATA command.
  769.      *
  770.      * @param string $data  The message body to send.
  771.      *
  772.      * @return mixed Returns a PEAR_Error with an error message on any
  773.      *               kind of failure, or true on success.
  774.      * @access public
  775.      * @since  1.0
  776.      */
  777.     function data($data)
  778.     {
  779.         /* RFC 1870, section 3, subsection 3 states "a value of zero
  780.          * indicates that no fixed maximum message size is in force".
  781.          * Furthermore, it says that if "the parameter is omitted no
  782.          * information is conveyed about the server's fixed maximum
  783.          * message size". */
  784.         if (isset($this->_esmtp['SIZE']) && ($this->_esmtp['SIZE'] > 0)) {
  785.             if (strlen($data) >= $this->_esmtp['SIZE']) {
  786.                 $this->disconnect();
  787.                 return PEAR::raiseError('Message size excedes the server limit');
  788.             }
  789.         }
  790.  
  791.         /* Quote the data based on the SMTP standards. */
  792.         $this->quotedata($data);
  793.  
  794.         if (PEAR::isError($error = $this->_put('DATA'))) {
  795.             return $error;
  796.         }
  797.         if (PEAR::isError($error = $this->_parseResponse(354))) {
  798.             return $error;
  799.         }
  800.  
  801.         if (PEAR::isError($result = $this->_send($data . "\r\n.\r\n"))) {
  802.             return $result;
  803.         }
  804.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  805.             return $error;
  806.         }
  807.  
  808.         return true;
  809.     }
  810.  
  811.     /**
  812.      * Send the SEND FROM: command.
  813.      *
  814.      * @param string The reverse path to send.
  815.      *
  816.      * @return mixed Returns a PEAR_Error with an error message on any
  817.      *               kind of failure, or true on success.
  818.      * @access public
  819.      * @since  1.2.6
  820.      */
  821.     function sendFrom($path)
  822.     {
  823.         if (PEAR::isError($error = $this->_put('SEND', "FROM:<$path>"))) {
  824.             return $error;
  825.         }
  826.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  827.             return $error;
  828.         }
  829.  
  830.         return true;
  831.     }
  832.  
  833.     /**
  834.      * Backwards-compatibility wrapper for sendFrom().
  835.      *
  836.      * @param string The reverse path to send.
  837.      *
  838.      * @return mixed Returns a PEAR_Error with an error message on any
  839.      *               kind of failure, or true on success.
  840.      *
  841.      * @access      public
  842.      * @since       1.0
  843.      * @deprecated  1.2.6
  844.      */
  845.     function send_from($path)
  846.     {
  847.         return sendFrom($path);
  848.     }
  849.  
  850.     /**
  851.      * Send the SOML FROM: command.
  852.      *
  853.      * @param string The reverse path to send.
  854.      *
  855.      * @return mixed Returns a PEAR_Error with an error message on any
  856.      *               kind of failure, or true on success.
  857.      * @access public
  858.      * @since  1.2.6
  859.      */
  860.     function somlFrom($path)
  861.     {
  862.         if (PEAR::isError($error = $this->_put('SOML', "FROM:<$path>"))) {
  863.             return $error;
  864.         }
  865.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  866.             return $error;
  867.         }
  868.  
  869.         return true;
  870.     }
  871.  
  872.     /**
  873.      * Backwards-compatibility wrapper for somlFrom().
  874.      *
  875.      * @param string The reverse path to send.
  876.      *
  877.      * @return mixed Returns a PEAR_Error with an error message on any
  878.      *               kind of failure, or true on success.
  879.      *
  880.      * @access      public
  881.      * @since       1.0
  882.      * @deprecated  1.2.6
  883.      */
  884.     function soml_from($path)
  885.     {
  886.         return somlFrom($path);
  887.     }
  888.  
  889.     /**
  890.      * Send the SAML FROM: command.
  891.      *
  892.      * @param string The reverse path to send.
  893.      *
  894.      * @return mixed Returns a PEAR_Error with an error message on any
  895.      *               kind of failure, or true on success.
  896.      * @access public
  897.      * @since  1.2.6
  898.      */
  899.     function samlFrom($path)
  900.     {
  901.         if (PEAR::isError($error = $this->_put('SAML', "FROM:<$path>"))) {
  902.             return $error;
  903.         }
  904.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  905.             return $error;
  906.         }
  907.  
  908.         return true;
  909.     }
  910.  
  911.     /**
  912.      * Backwards-compatibility wrapper for samlFrom().
  913.      *
  914.      * @param string The reverse path to send.
  915.      *
  916.      * @return mixed Returns a PEAR_Error with an error message on any
  917.      *               kind of failure, or true on success.
  918.      *
  919.      * @access      public
  920.      * @since       1.0
  921.      * @deprecated  1.2.6
  922.      */
  923.     function saml_from($path)
  924.     {
  925.         return samlFrom($path);
  926.     }
  927.  
  928.     /**
  929.      * Send the RSET command.
  930.      *
  931.      * @return mixed Returns a PEAR_Error with an error message on any
  932.      *               kind of failure, or true on success.
  933.      * @access public
  934.      * @since  1.0
  935.      */
  936.     function rset()
  937.     {
  938.         if (PEAR::isError($error = $this->_put('RSET'))) {
  939.             return $error;
  940.         }
  941.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  942.             return $error;
  943.         }
  944.  
  945.         return true;
  946.     }
  947.  
  948.     /**
  949.      * Send the VRFY command.
  950.      *
  951.      * @param string The string to verify
  952.      *
  953.      * @return mixed Returns a PEAR_Error with an error message on any
  954.      *               kind of failure, or true on success.
  955.      * @access public
  956.      * @since  1.0
  957.      */
  958.     function vrfy($string)
  959.     {
  960.         /* Note: 251 is also a valid response code */
  961.         if (PEAR::isError($error = $this->_put('VRFY', $string))) {
  962.             return $error;
  963.         }
  964.         if (PEAR::isError($error = $this->_parseResponse(array(250, 252)))) {
  965.             return $error;
  966.         }
  967.  
  968.         return true;
  969.     }
  970.  
  971.     /**
  972.      * Send the NOOP command.
  973.      *
  974.      * @return mixed Returns a PEAR_Error with an error message on any
  975.      *               kind of failure, or true on success.
  976.      * @access public
  977.      * @since  1.0
  978.      */
  979.     function noop()
  980.     {
  981.         if (PEAR::isError($error = $this->_put('NOOP'))) {
  982.             return $error;
  983.         }
  984.         if (PEAR::isError($error = $this->_parseResponse(250))) {
  985.             return $error;
  986.         }
  987.  
  988.         return true;
  989.     }
  990.  
  991.     /**
  992.      * Backwards-compatibility method.  identifySender()'s functionality is
  993.      * now handled internally.
  994.      *
  995.      * @return  boolean     This method always return true.
  996.      *
  997.      * @access  public
  998.      * @since   1.0
  999.      */
  1000.     function identifySender()
  1001.     {
  1002.         return true;
  1003.     }
  1004.  
  1005. }
  1006.